﻿#include "HistoryDialog.h"
#include <QRadioButton.h>
#include <QDateTimeEdit>
#include <QFileDialog>
#include <QLabel>
#include <QLineEdit>
#include <QMessageBox>
#include <QPushButton>
#include <QScrollArea>
#include "Custom/CircleButton.h"
#include "Model/DataCenter.h"
#include "SoundRecorder.h"
#include "Toast.h"
using namespace model;

//////////////////////////////////////////
/// 点击历史按钮时显示的窗口
/// 支持按关键字查询和按时间查询
//////////////////////////////////////////
HistoryDialog::HistoryDialog(QWidget* parent)
    : QDialog(parent)
{
    init_base_ui();
    init_scroll_area_ui();
    connect_signals();
#ifdef TEST_UI
    /* 添加测试数据 */
    model::Message msg;
    for (int i = 0; i < 20; ++i) {
        msg.message_type     = model::MessageType::TEXT_TYPE;
        msg.sender.avatar    = QIcon(":/image/chocolate.png");
        msg.chat_session_id  = "session_" + QString::number(i);
        msg.sender.user_id   = "user_" + QString::number(i);
        msg.sender.nick_name = "User " + QString::number(i);
        msg.content          = ("This is a test message " + QString::number(i)).toUtf8();
        msg.time             = model::get_formate_time(model::get_current_time_stamp());
        add_item(msg);
    }
#endif  // TEST_UI
}

/// @brief 初始化基本UI
void HistoryDialog::init_base_ui()
{
    /* 初始化基本属性 */
    this->setWindowTitle("聊天记录");
    this->setFixedSize(660, 720);
    this->setWindowIcon(QIcon(":/image/logo.png"));
    this->setAttribute(Qt::WA_DeleteOnClose);
    this->setObjectName("out_widget");
    this->setStyleSheet(
        "#out_widget{"
        "background-color: #ffffff;"
        "}");
    g_layout = new QGridLayout();
    g_layout->setContentsMargins(15, 10, 10, 10);
    g_layout->setSpacing(10);
    this->setLayout(g_layout);
    /* 一些常量定义 */
    const static int HEIGHT = 30;
    const static int WIDTH  = 50;
    /* 样式设置 */
    this->setStyleSheet(
        "QWidget {"
        "background-color: #FFFFFF;"
        "border: none;"
        "}"
        "QRadioButton {"
        "spacing: 7px;"
        "font-size: 14px;"
        "}"
        "QRadioButton::indicator {"
        "width: 18px;"
        "height: 18px;"
        "image: url(:/image/unchecked.png);"
        "}"
        "QRadioButton::indicator:checked {"
        "width: 18px;"
        "height: 18px;"
        "image: url(:/image/checked.png);"
        "}");
    /* 创建单选框 */
    keyword_radio = new QRadioButton("按关键字查询");
    time_radio    = new QRadioButton("按时间查询");
    keyword_radio->setChecked(true);  // 默认选中按关键字查询
    keyword_radio->setFixedHeight(HEIGHT);
    time_radio->setFixedHeight(HEIGHT);
    /* 搜索框和 spacer和搜索按钮 */
    line_edit = new QLineEdit();
    line_edit->setPlaceholderText("输入搜索关键字");
    line_edit->setStyleSheet(get_line_edit_style());
    line_edit->setFixedHeight(HEIGHT);
    spacer_item      = new QSpacerItem(10, 0, QSizePolicy::Fixed, QSizePolicy::Minimum);
    search_btn       = new QPushButton("搜索");
    QString blue_btn = get_blue_button_style();
    blue_btn.replace("QPushButton {", "QPushButton { border-radius: 5px; ");
    search_btn->setStyleSheet(blue_btn);
    search_btn->setFixedSize(WIDTH, HEIGHT);
    /* 两个日期时间选择器和对应的QLabel */
    start_time = new QDateTimeEdit();
    start_time->setStyleSheet(DATE_TIME_EDIT_STYLE);
    start_time->setDisplayFormat("yyyy-MM-dd HH:mm");
    start_time->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
    start_time_label = new QLabel("起始时间: ");
    start_time->setFixedHeight(HEIGHT);
    end_time = new QDateTimeEdit();
    end_time->setStyleSheet(DATE_TIME_EDIT_STYLE);
    end_time->setDisplayFormat("yyyy-MM-dd HH:mm");
    end_time->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
    end_time_label = new QLabel("结束时间: ");
    end_time->setFixedHeight(HEIGHT);
    end_time->setDateTime(QDateTime::currentDateTime());                // 默认结束时间为今天
    start_time->setDateTime(QDateTime::currentDateTime().addDays(-7));  // 默认起始时间为7天前
    /* 设置 time的 QLabel的Size */
    QFontMetrics font_metrics(start_time_label->font());
    QSize        label_size = font_metrics.size(Qt::TextSingleLine, start_time_label->text());
    start_time_label->setFixedSize(QSize(label_size.width() + 10, HEIGHT));
    end_time_label->setFixedSize(QSize(label_size.width() + 10, HEIGHT));
    /* 向布局管理器中添加元素 */
    g_layout->addWidget(keyword_radio, 0, 0, 1, 1, Qt::AlignTop);
    g_layout->addItem(spacer_item, 0, 1, 1, 1);  // 增加两个单选按钮之间的间距
    g_layout->addWidget(time_radio, 0, 2, 1, 1, Qt::AlignTop);
    g_layout->addWidget(line_edit, 1, 0, 1, 7, Qt::AlignTop);
    g_layout->addWidget(search_btn, 1, 7, 1, 1, Qt::AlignTop);
}

/// @brief 初始化滚动区域的UI
void HistoryDialog::init_scroll_area_ui()
{
    QScrollArea* s_area = new QScrollArea();
    s_area->setStyleSheet(SCROLL_STYLE);
    s_area->setWidgetResizable(true);
    s_area->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);  // Expanding便于把搜索框顶上去
    QWidget* container = new QWidget();
    container->setStyleSheet(
        "QWidget {"
        "background-color: #FFFFFF;"
        "border:none;"
        "}");
    s_area->setWidget(container);
    v_layout_scroll = new QVBoxLayout();
    v_layout_scroll->setContentsMargins(0, 0, 0, 0);
    v_layout_scroll->setSpacing(0);
    v_layout_scroll->setAlignment(Qt::AlignTop);
    container->setLayout(v_layout_scroll);
    /* 向布局管理器中添加元素 */
    g_layout->addWidget(s_area, 2, 0, 1, 8);
}

/// @brief 处理信号槽连接
void HistoryDialog::connect_signals()
{
    /* 点击按时间查询 */
    connect(time_radio, &QRadioButton::toggled, this, [this](bool checked) {
        if (checked) {
            /* 隐藏另一个, 显示我自己 */
            g_layout->removeWidget(line_edit);
            g_layout->removeWidget(search_btn);
            line_edit->hide();
            search_btn->hide();
            g_layout->addWidget(start_time_label, 1, 0, 1, 1, Qt::AlignTop);
            g_layout->addWidget(start_time, 1, 1, 1, 3, Qt::AlignTop);
            g_layout->addWidget(end_time_label, 1, 4, 1, 1, Qt::AlignTop);
            g_layout->addWidget(end_time, 1, 5, 1, 3, Qt::AlignTop);
            start_time_label->show();
            start_time->show();
            end_time_label->show();
            end_time->show();
        } else {
            // do nothing for now
        }
    });
    /* 点击按关键字查询 */
    connect(keyword_radio, &QRadioButton::toggled, this, [this](bool checked) {
        if (checked) {
            /* 隐藏另一个, 显示我自己 */
            g_layout->removeWidget(start_time_label);
            g_layout->removeWidget(start_time);
            g_layout->removeWidget(end_time_label);
            g_layout->removeWidget(end_time);
            start_time_label->hide();
            start_time->hide();
            end_time_label->hide();
            end_time->hide();
            g_layout->addWidget(line_edit, 1, 0, 1, 7, Qt::AlignTop);
            g_layout->addWidget(search_btn, 1, 7, 1, 1, Qt::AlignTop);
            line_edit->show();
            search_btn->show();
        } else {
            // do nothing for now
        }
    });
    /* 点击搜索按钮 */
    connect(search_btn, &QPushButton::clicked, this, &HistoryDialog::handle_clicked_search_btn);
    /* 时间改变了 */
    connect(end_time, &QDateTimeEdit::dateTimeChanged, this, &HistoryDialog::handle_date_changed);
}

/// @brief 处理点击搜索按钮的槽, 根据不同的条件进行搜索
void HistoryDialog::handle_clicked_search_btn()
{
    DataCenter*   data_center    = DataCenter::get_instance();
    const QString cur_session_id = data_center->get_cur_session_id();
    connect(data_center, &DataCenter::search_history_message_done, this, [=]() {
        clear();
        QList<Message>* message_list = data_center->get_search_message_result();
        if (message_list == nullptr) {
            LOG() << "message list is nullptr!!";
            return;
        }
        for (const auto& msg : *message_list) {
            add_item(msg);
        }
    });
    QString key_word = line_edit->text();
    if (key_word.trimmed() == "") {
        return;
    }
    data_center->search_history_message_async(cur_session_id, key_word);
}

/// @brief 当时间改变时调用的槽函数
void HistoryDialog::handle_date_changed()
{
    DataCenter*   data_center    = DataCenter::get_instance();
    const QString cur_session_id = data_center->get_cur_session_id();
    connect(data_center, &DataCenter::search_history_message_done, this, [=]() {
        clear();
        QList<Message>* message_list = data_center->get_search_message_result();
        if (message_list == nullptr) {
            LOG() << "message list is nullptr!!";
            return;
        }
        for (const auto& msg : *message_list) {
            add_item(msg);
        }
    });
    qint64 start_time_stamp = start_time->dateTime().toSecsSinceEpoch();
    qint64 end_time_stamp   = end_time->dateTime().toSecsSinceEpoch();
    if (end_time_stamp <= start_time_stamp) {
        Toast::showMessage("结束时间不能早于开始时间");
        return;
    }
    data_center->search_history_message_by_time_async(cur_session_id, start_time_stamp, end_time_stamp);
}

/// @brief 添加一条历史记录项
void HistoryDialog::add_item(const model::Message& msg)
{
    v_layout_scroll->addWidget(HistoryDialogItem::make_history_item(msg));
}

/// @brief 全部清除历史记录项
void HistoryDialog::clear()
{
    for (int i = v_layout_scroll->count() - 1; i >= 0; --i) {
        auto item = v_layout_scroll->takeAt(i);
        if (item != nullptr) {
            delete item;
        } else {
            LOG() << "Item is nullptr...";
        }
    }
}

/// @brief 构建一条历史记录项, 要显示头像, 昵称, 时间, 内容等信息
HistoryDialogItem* HistoryDialogItem::make_history_item(const model::Message& msg)
{
    /* 创建对象和布局管理器 */
    HistoryDialogItem* item = new HistoryDialogItem();
    item->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);  // 垂直方向上自适应内容高度
    QGridLayout* layout = new QGridLayout();
    layout->setContentsMargins(10, 10, 10, 10);
    layout->setSpacing(10);
    item->setLayout(layout);
    /* 创建头像按钮 */
    CircleButton* avatar_btn = new CircleButton();
    avatar_btn->setFixedSize(50, 50);
    avatar_btn->setIconSize(QSize(50, 50));
    avatar_btn->setIcon(msg.sender.avatar);
    /* 创建昵称和时间标签 */
    QLabel* name_time_label = new QLabel(msg.sender.nick_name + " " + msg.time);
    name_time_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
    name_time_label->setStyleSheet(
        "QLabel {"
        "font-size: 12px;"
        "}");
    /* 创建消息体, 需要根据不同消息类型显示不同内容 */
    switch (msg.message_type) {
    case model::MessageType::TEXT_TYPE: {
        /* 文本消息 */
        QLabel* content_label = new QLabel(msg.content);
        content_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
        content_label->setWordWrap(true);
        content_label->adjustSize();  // QLabel根据内容自适应大小
        content_label->setStyleSheet(
            "QLabel {"
            "font-size: 14px;"
            "}");
        layout->addWidget(content_label, 1, 2, 1, 6, Qt::AlignTop | Qt::AlignLeft);
        break;
    }
    case model::MessageType::IMAGE_TYPE: {
        /* 图片消息 */
        // LOG() << "Image message, file_id: " << msg.file_id;
        ImageButton* image_btn = new ImageButton(msg);
        layout->addWidget(image_btn, 1, 2, 1, 6, Qt::AlignTop | Qt::AlignLeft);
        break;
    }
    case model::MessageType::FILE_TYPE: {
        /* 文件消息 */
        // LOG() << "File message, file_id: " << msg.file_id << ", file_name: " << msg.file_name;
        FileLabel* file_label = new FileLabel(msg);
        layout->addWidget(file_label, 1, 2, 1, 6, Qt::AlignTop | Qt::AlignLeft);
        break;
    }
    case model::MessageType::SPEECH_TYPE: {
        /* 语音消息 */
        // LOG() << "Speech message, file_id: " << msg.file_id;
        SpeechLabel* speech_label = new SpeechLabel(msg);
        layout->addWidget(speech_label, 1, 2, 1, 6, Qt::AlignTop | Qt::AlignLeft);
        break;
    }
    case model::MessageType::UNKNOW:
        /* 未知消息类型 */
        LOG() << "Unknown message type!";
        break;
    default:
        LOG() << "Invalid message type!";
        break;
    }

    /* 将头像和昵称放到布局管理器中 */
    layout->addWidget(avatar_btn, 0, 0, 2, 2, Qt::AlignTop);
    layout->addWidget(name_time_label, 0, 2, 1, 1, Qt::AlignBottom);
    return item;
}

///////////////////////////////////////
/// 图片Button, 用于显示图片消息
///////////////////////////////////////
ImageButton::ImageButton(const model::Message& msg)
{
    this->file_id    = msg.file_id;
    this->image_data = msg.content;
    if (this->image_data.isEmpty()) {
        // 消息中没有图片数据, 需要从服务器获取
        DataCenter* data_center = DataCenter::get_instance();
        connect(data_center, &DataCenter::get_single_file_done, this, &ImageButton::update_content);
        data_center->get_single_file_async(this->file_id);
    } else {
        this->update_content(this->file_id, this->image_data);
    }
}

/// @brief 根据从服务器获取的图片数据更新显示内容
///        如果是自己发送的图片, 则消息中已经包含图片数据, 也调用这个函数直接显示
void ImageButton::update_content(const QString& file_id, const QByteArray& image_data)
{
    if (file_id != this->file_id) {
        return;
    }
    this->file_id    = file_id;
    this->image_data = image_data;
    QImage image;
    image.loadFromData(image_data);
    QPixmap pixmap = QPixmap::fromImage(image);
    if (pixmap.width() >= 300) {
        // 图片过大, 进行缩放
        pixmap = pixmap.scaledToWidth(300, Qt::SmoothTransformation);
    }
    this->setIcon(pixmap);
    this->setIconSize(pixmap.size());
    this->resize(pixmap.size());
}

///////////////////////////////////////
/// 用于显示文件消息的Label
///////////////////////////////////////
FileLabel::FileLabel(const model::Message& msg)
{
    this->file_id   = msg.file_id;
    this->file_name = msg.file_name;
    this->file_data = msg.content;
    this->setWordWrap(true);
    this->adjustSize();
    this->setText("[文件]: " + file_name);
    if (this->file_data.isEmpty()) {
        // 消息中没有文件数据, 需要从服务器获取
        DataCenter* data_center = DataCenter::get_instance();
        connect(data_center, &DataCenter::get_single_file_done, this, &FileLabel::update_content);
        data_center->get_single_file_async(this->file_id);
    } else {
        this->update_content(this->file_id, this->file_data);
    }
    this->setStyleSheet(R"(
        QLabel {
            background-color: #e3f2fd;
            border: 1px solid #bbdefb;
            border-radius: 6px;
            padding: 8px 12px;
            color: #1565c0;
            font-weight: 500;
        }
        QLabel:hover {
            background-color: #bbdefb;
            border-color: #90caf9;
        }
    )");
}

/// @brief 点击文件标签时触发, 弹出文件保存对话框
void FileLabel::mousePressEvent(QMouseEvent* event)
{
    if (event->button() == Qt::LeftButton) {
        QString file_path = QFileDialog::getSaveFileName(this, "保存文件", file_name);
        if (file_path.isEmpty()) {
            return;
        }
        QFile file(file_path);
        if (!file.open(QIODevice::WriteOnly)) {
            QMessageBox::warning(this, "错误", "无法保存文件: " + file.errorString());
            return;
        }
        if (file_data.isEmpty()) {
            QMessageBox::warning(this, "错误", "文件数据为空，无法保存！");
            return;
        }
        file.write(file_data);
        file.close();
    }
}

void FileLabel::update_content(const QString& file_id, const QByteArray& file_content)
{
    if (file_id != this->file_id) {
        return;
    }
    this->file_data = file_content;
}

///////////////////////////////////////
/// 用于显示语音消息的Label
///////////////////////////////////////
SpeechLabel::SpeechLabel(const model::Message& msg)
{
    this->file_id     = msg.file_id;
    this->speech_data = msg.content;
    this->setWordWrap(true);
    this->adjustSize();
    this->setText("[||语音||");
    if (this->speech_data.isEmpty()) {
        // 消息中没有文件数据, 需要从服务器获取
        DataCenter* data_center = DataCenter::get_instance();
        connect(data_center, &DataCenter::get_single_file_done, this, &SpeechLabel::update_content);
        data_center->get_single_file_async(this->file_id);
    } else {
        this->update_content(this->file_id, this->speech_data);
    }
    this->setStyleSheet(R"(
        QLabel {
            background-color: #f3e5f5;
            border: 1px solid #e1bee7;
            border-radius: 6px;
            padding: 8px 12px;
            color: #7b1fa2;
            font-weight: 500;
        }
        QLabel:hover {
            background-color: #e1bee7;
            border-color: #ce93d8;
        }
    )");
}

void SpeechLabel::mousePressEvent(QMouseEvent* event)
{
    // 播放语音
    if (event->button() == Qt::LeftButton) {
        SoundRecorder* recorder = SoundRecorder::get_instance();
        // 播放语音
        if (speech_data.isEmpty()) {
            QMessageBox::warning(this, "错误", "语音数据为空，无法播放！");
            return;
        } else if (!recorder->is_playing()) {
            // 没在播放, 可以播放
            connect(recorder, &SoundRecorder::sound_play_done, this, [this]() {
                this->setText("[||语音||]");
                this->update();
            });
            this->setText("[>>播放中>>]");
            recorder->start_play(speech_data);
        } else {
            // 在播放, 停止播放
            this->setText("[||语音||]");
            recorder->stop_play();
        }
    }
}

void SpeechLabel::update_content(const QString& file_id, const QByteArray& speech_content)
{
    if (file_id != this->file_id) {
        return;
    }
    this->speech_data = speech_content;
}
